package main

import (
	"math/rand"
	"sort"
	"strings"
	"time"
)

var ranks = []string{"2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A"}
var suits = []string{"♠", "♥", "♦", "♣"}

type Card struct {
	Rank int // 2-9, 10, 11, 12, 13, 14 = J Q K A
	Suit int // 1,2,3,4 = ♠ ♥ ♣ ♦
}

/*
用golang写一个函数，把手牌按rank大小倒序排列。输入是[3]Card，输出是排序后的[3]Card

	type Card struct {
		Suit int
		Rank int
	}
*/
func sortCards(cards [3]Card) [3]Card {
	sort.Slice(cards[:], func(i, j int) bool {
		return cards[i].Rank > cards[j].Rank
	})

	return cards
}

/*
golang在数组中查询某个值的index
*/
func indexOf(arr []string, target string) int {
	for i, val := range arr {
		if val == target {
			return i
		}
	}
	return -1 // 如果未找到目标值，返回-1
}

/*
牌型大小判定规则如下：
豹子：三张牌相同的情况，如AAA、222等。
同花顺：即相同花色的顺子，如红心10、红心J、红心Q等。
同花：即三张牌的花色都相同，但不是顺子，如红心A、红心5、红心K等。
顺子：即三张牌是连续的，但不是同花的，如红心8、黑桃9、方块10等。
对子：即两张牌相同，另一张不同，如红心8、黑桃8、方块J等。
单张：即三张牌都不相同，没有组成任何牌型的情况。
牌型大小的比较是按照上述顺序进行的，即豹子最大，单张最小。

当两个玩家的牌型相同时，比较牌面的大小，如AAA比KKK大，顺子按照最大的一张牌进行比较，对子则比较对子的大小，单张则比较最大的一张牌的大小。
如果两个玩家的牌型和牌面大小都相同，则称为平局。
*/
func compare(c1, c2 []string) int {
	return value(c1) - value(c2)
}

// ["♣A","♠10","♠K"] ==> [{14, 4}, {10, 1}, {13, 1}]
func str2card(s []string) [3]Card {
	var c [3]Card
	for i := 0; i < 3; i++ {
		part := strings.Split(s[i], ".")

		idx1 := indexOf(suits, part[0]) // 花色
		idx2 := indexOf(ranks, part[1]) // 点数
		c[i] = Card{idx2 + 2, idx1 + 1} // rank[0]="2"
	}
	return sortCards(c)
}

// 计算牌面价值
func value(c []string) int {
	s := str2card(c)

	// 把排序后的牌转化成数字值（13张牌,使用16进制）
	v := ((s[0].Rank*16 + s[1].Rank) * 16) + s[2].Rank

	if isPair(s) {
		// 判断对子的点数 [♦.10 ♠.10 ♥.6] vs [♠.A ♦.2 ♥.2]
		if s[0].Rank == s[1].Rank {
			v += 0x1000 * s[0].Rank
		} else {
			v += 0x1000 * s[2].Rank
		}
	}
	if isStraight(s) {
		v += 0x10000
	}
	if isFlush(s) {
		v += 0x20000
	}
	if isStraightFlush(s) {
		v += 0x40000
	}
	if isTriple(s) {
		v += 0x80000
	}

	return v
}

// 计算对手拿到比我的牌更大的概率：未测试通过，结果不准确
func ratio(c []string) float64 {
	s := str2card(c)

	// 比当前点数更大的牌的数量
	p0 := 14 - s[0].Rank
	p1 := 14 - s[1].Rank
	p2 := 14 - s[2].Rank

	x := 0
	if isTriple(s) {
		x += p0
		return float64(x) / 22100.0
	} else {
		x += 13
	}

	if isStraightFlush(s) {
		x += p0 * 4 // 4种花色的同花顺
		return float64(x) / 22100.0
	} else {
		x += 40
	}

	if isFlush(s) {
		x += p0 * 13 * 12
		x += p1 * 12
		x += p2
		return float64(x) / 22100.0
	} else {
		x += 1144 - 40
	}

	if isStraight(s) {
		x += p0 * 4 * 4 * 4 // 3张牌，每张牌有4种花色可选
		return float64(x) / 22100.0
	} else {
		x += 640 - 40
	}

	if isPair(s) {
		if p0 == p1 {
			x += p1 * 6 * 48 // 从4张K中选2张C(4,2)=6；再从不是K的牌中选1张单牌（52-4=48）
			x += p2
		} else {
			x += p1 * 6 * 48
			x += p0
		}
		return float64(x) / 22100.0
	} else {
		x += 3744 - 13
	}

	// 计算单牌
	x += p0 * 52 * 51
	x += p1 * 51
	x += p2
	return float64(x) / 22100.0

}

func isTriple(cards [3]Card) bool {
	return cards[0].Rank == cards[1].Rank && cards[1].Rank == cards[2].Rank
}

func isStraightFlush(cards [3]Card) bool {
	return isFlush(cards) && isStraight(cards)
}

func isFlush(cards [3]Card) bool {
	return cards[0].Suit == cards[1].Suit && cards[1].Suit == cards[2].Suit
}

func isStraight(cards [3]Card) bool {
	sort.Slice(cards[:], func(i, j int) bool {
		return cards[i].Rank < cards[j].Rank
	})

	return cards[0].Rank+1 == cards[1].Rank && cards[1].Rank+1 == cards[2].Rank
}

func isPair(cards [3]Card) bool {
	return cards[0].Rank == cards[1].Rank || cards[1].Rank == cards[2].Rank || cards[0].Rank == cards[2].Rank
}

// implement a card dealer in golang, deal 3 random cards for each player
// 发牌程序
func deal(numPlayers int, numCards int) [][]string {

	deck := []string{}

	for _, rank := range ranks {
		for _, suit := range suits {
			deck = append(deck, suit+"."+rank)
		}
	}

	// Shuffle shuffles the deck of cards
	rand.Seed(time.Now().UnixNano())

	for i := range deck {
		j := rand.Intn(i + 1)
		deck[i], deck[j] = deck[j], deck[i]
	}

	cards := make([][]string, numPlayers)

	for i := 0; i < numCards; i++ {
		for j := 0; j < numPlayers; j++ {
			cards[j] = append(cards[j], deck[i*numPlayers+j])
		}
	}

	return cards

}
